/*************************************************************************
	> File Name: TcpServer.hpp
	> Author: H.M. Lau
	> Mail: hm.lau@outlook.com
	> Created Time: 2023/10/15 15:19
 ************************************************************************/

#pragma once

#include "Sock.hpp"
#include <vector>
#include <functional>
#include <pthread.h>

namespace halil
{
    using func_t = std::function<void(int)>;

    class TcpServer;

    struct ThreadData {
        int _sock;
        TcpServer* _server;
        ThreadData(const int sock, TcpServer* server):_sock(sock), _server(server)
        {}
    };

    class TcpServer
    {
    public:
        TcpServer (const uint16_t& port, const std::string& ip = "0.0.0.0")
        {
            _listensock = _sock.Socket();
            _sock.Bind(_listensock, port, ip);
            _sock.Listen(_listensock);
        }

        void BindService(func_t func)
        {
            _func.push_back(func);
        }

        void Excute(const int sock) const
        {
            for (const auto& f : _func) {
                f(sock);
            }
        }

        void Start() 
        {
            while (1) {
                std::string cli_ip = "";
                uint16_t cli_port = 0;
                int sock = _sock.Accept(_listensock, &cli_ip, &cli_port);
                if (sock == -1) {
                    continue;
                }
                logMessage(NORMAL, "Create new link success, sock:%d", sock);
                pthread_t tid;
                ThreadData* td = new ThreadData(sock, this);
                pthread_create(&tid, nullptr, _ThreadRoutine, td);
            }
        }
    
    private:
        static void* _ThreadRoutine(void* args) 
        {
            pthread_detach(pthread_self());
            ThreadData* td = static_cast<ThreadData*>(args);
            td->_server->Excute(td->_sock);
            return nullptr;
        }

        int _listensock;
        halil::Sock _sock;
        std::vector<func_t> _func;
    };
}
